//
// Created by luo on 2022-10-10.
//
#include "../opencv/OpenCv.h"
#include "opencv2/opencv_modules.hpp"
#include "opencv2/opencv.hpp"
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>



//12.1 OpenCV与传统机器学习
/*
 * 在人工智能的发展过程中，深度学习与图像处理相结合弥补了传统图像处理在分类、识别等领域的不足
 * 本节将介绍OpenCV与机器学习的相关函数与方法，包含 K均值、K邻域、决策树、随机森林、支持向量机等
 * 还介绍OpenCV4与深度学习结合使用的内容
 * */

/*
 * OpenCV 中有两个关于机器学习的模块，分别是：
    Machine Learning (ml)模块     传统机器学习算法相关函数
    Deep Neural Networks(dnn)模块 深度神经网络相关函数
 * */

//12.1 K均值
/*
 * K均值(Kmeans) 是最简单的聚类方法之一，是一种无监督学习均值聚类的原理:
 * ---通过指定种类数目对数据进行聚类，例如根据颜色将围棋棋盘上的棋子分成两类---
    第一步:指定将数据聚类成k类，并随机生成k个中心点。
    第二步:遍历所有数据，根据数据与中心的位置关系将每个数据归类到不同的中心
    第三步:计算每个聚类的平均值，并将均值作为新的中心点
    第四步:重复第二步和第三步，直到每个聚类中心点的坐标收敛，输出聚类结果

 *  double cv::kmeans(cv::InputArray data, int K,
                    cv::InputOutputArray bestLabels,
                    cv::TermCriteria criteria,
                    int attempts,
                    int flags,
                    cv::OutputArray centers) {}
 * data 需要聚类的输入数据，数据必须为行排列，即每一行是一个单独的数据.
   K 将数据聚类的种类数目 >0
   bestLabels 存储每个数据聚类结果索引的矩阵或向量
   criteria: 垂代算法终止条件
   attempts 表示采样不同初始化标签尝试的次数
   flags 每类中心初始化方法标志，可选标志及其含义在表 12-1 中给出. 0 1 2 随机 第一次用户，后续随机，使用Arthur
   centers 最终聚类后的每个类的中心位置坐标.
 * 该函数实现对输入数据的聚类 并将聚类结果存放在与数据同尺寸的索引矩阵中.
 * */

//给出了对图像中像素点坐标进行分类的示例程序
/*
 * 首先在 个区域内随机生成数量不等的点 ，并将这些点在图像中的坐标
    作为需要聚类的数据输入给 kmeansO 函数，用不同的颜色表示不同的分类结果 并以每一类的中心
    作为圆心绘制圆形 直观地表示出数据的分类结果
 * */
void QuickDemo::my_KMeanPoints(Mat &mat)
{
    cv::Mat img(500,500,CV_8UC3,Scalar(255,255,255));
    RNG rng(10000);

    Scalar colorLut[3] = {
            Scalar(0,0,255),
            Scalar(0,255,0),
            Scalar(255,0,0),
    };

    //设置3个点集，并且每个点集中点的数目随机
    int number = 3;
    int Points1 = rng.uniform(20 , 200);
    int Points2 = rng.uniform(20 , 200);
    int Points3 = rng.uniform(20 , 200);
    int Points_num =Points1 + Points2 + Points3;
    Mat Points(Points_num,1, CV_32FC2);

    int i = 0;
    for(;i < Points1; i++)
    {
        Point2f pts;
        pts.x = rng.uniform(100,200);
        pts.y = rng.uniform(100,200);
        Points.at<Point2f>(i,0) = pts;
    }
    for(;i < Points1+Points2; i++)
    {
        Point2f pts;
        pts.x = rng.uniform(300,400);
        pts.y = rng.uniform(100,300);
        Points.at<Point2f>(i,0) = pts;
    }
    for(;i < Points1+Points2+Points3; i++)
    {
        Point2f pts;
        pts.x = rng.uniform(100,200);
        pts.y = rng.uniform(390,490);
        Points.at<Point2f>(i,0) = pts;
    }

    //使用K均值
    cv::Mat labels; //每个点所属种类
    cv::Mat centers; //每类点的中心位置坐标
    cv::kmeans(Points,number,labels,TermCriteria(TermCriteria::EPS+TermCriteria::COUNT,10,0.1),
               3,KMEANS_PP_CENTERS,centers);

    //根据分类为每个点设置不同颜色
    img = Scalar::all(255);
    for(auto i = 0; i<Points_num;i++)
    {
        int index = labels.at<int>(i);
        Point point = Points.at<Point2f>(i);
        circle(img,point,2,colorLut[index],-1,4);
    }

    //以每个聚类的中心为圆心来绘制圆
    for(auto i = 0; i < centers.rows; i++)
    {
        int x = centers.at<float>(i,0);
        int y = centers.at<float>(i,1);
        std::cout<<"第"<<i+1<<"类的中心坐标:x= "<<x<<" y="<<y<<std::endl;
        circle(img,Point(x,y),50,colorLut[i],-1,LINE_AA);
    }
    cv::imshow("img",img);
    cv::waitKey(0);
    return;
}
//根据K均值聚类可以实现基于像素值 图像分割 与坐标点聚类相似， 图像分割时的聚类数据是每个像素的像素值.

void QuickDemo::my_KMeanImage(Mat &mat)
{

}

//12.1.2 K近邻

//12.1.3 决策树

//12.1.4 随机森林

//12.1.5 支持向量机


//12.2 OpenCV与深度神经网络应用实例
/*
 * 随着深度神经网络的发展 OpenCv4中已经有独立的模块专门用于实现各种深度学习的相关算法
 * */

//12.2.1 加载深度学习模型
/*
 * 深度学习中比较重要的部分是对模型的训练 模型训练完成后即可使用模型对新数据进行
    处理，例如识别图像中的物体、对图像中的人脸进行识别等.由于训练模型既耗费时间又容易
    失败，因此在实际使用过程中可以直接加载已有的模型 没必要每次都重新训练模型.

 * OpenCV4中提供了 dnn::readNet() 函数用于加载已经训练完成的模型
 * Net dnn::readNet(const cv::String &model,
                    const cv::String &config,
                    const cv::String &framework) {}
 * model 模型文件名称.
   config 配置文件名称.
   framework 框架种类.
 * 该函数可以加载已经完成训练的深度学习网络模型 一个Net类型的变量
 * */
//using namespace cv::dnn;
//
//void my_readNet()
//{
//    Net net;
//}




